/* parse the input, from python float to c double */ if (!PyArg_ParseTuple(args, "d", &value)) return NULL; /* if the above function returns -1, an appropriate Python exception will * have been set, and the function simply returns NULL */
/* call cos from libm */ answer = cos(value);
/* construct the output from cos, from c double to python float */ return Py_BuildValue("f", answer); }
/* parse single numpy array argument */ if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &in_array)) return NULL;
/* construct the output array, like the input array */ out_array = PyArray_NewLikeArray(in_array, NPY_ANYORDER, NULL, 0); if (out_array == NULL) return NULL;
/* create the iterators */ /* TODO: this iterator API is deprecated since 1.6 * replace in favour of the new NpyIter API */ in_iter = (PyArrayIterObject *)PyArray_IterNew((PyObject*)in_array); out_iter = (PyArrayIterObject *)PyArray_IterNew(out_array); if (in_iter == NULL || out_iter == NULL) goto fail;
/* iterate over the arrays */ while (in_iter->index < in_iter->size && out_iter->index < out_iter->size) { /* get the datapointers */ double * in_dataptr = (double *)in_iter->dataptr; double * out_dataptr = (double *)out_iter->dataptr; /* cosine of input into output */ *out_dataptr = cos(*in_dataptr); /* update the iterator */ PyArray_ITER_NEXT(in_iter); PyArray_ITER_NEXT(out_iter); }
/* clean up and return the result */ Py_DECREF(in_iter); Py_DECREF(out_iter); Py_INCREF(out_array); return out_array;
/* in case bad things happen */ fail: Py_XDECREF(out_array); Py_XDECREF(in_iter); Py_XDECREF(out_iter); return NULL; }
/* define functions in module */ static PyMethodDef CosMethods[] = { {"cos_func_np", cos_func_np, METH_VARARGS, "evaluate the cosine on a numpy array"}, {NULL, NULL, 0, NULL} };
/* module initialization */ PyMODINIT_FUNC
initcos_module_np(void) { (void) Py_InitModule("cos_module_np", CosMethods); /* IMPORTANT: this must be called */ import_array(); }
""" Example of wrapping cos function from math.h using ctypes. """
import ctypes from ctypes.util import find_library
# find and load the library libm = ctypes.cdll.LoadLibrary(find_library('m')) # set the argument type libm.cos.argtypes = [ctypes.c_double] # set the return type libm.cos.restype = ctypes.c_double
defcos_func(arg): ''' Wrapper for cos from math.h ''' return libm.cos(arg)
In [4]: cos_module.cos_func(1.0) Out[4]: 0.5403023058681398
In [5]: cos_module.cos_func(0.0) Out[5]: 1.0
In [6]: cos_module.cos_func(3.14159265359) Out[6]: -1.0
正如之前的例子,这个代码稍微健壮一些。尽管错误信息不怎么有用,因它并没告诉我们应该是什么类型。
1 2 3 4 5 6 7 8 9 10 11 12
In [7]: cos_module.cos_func('foo') --------------------------------------------------------------------------- ArgumentError Traceback (most recent call last) <ipython-input-7-11bee483665d> in <module>() ----> 1 cos_module.cos_func('foo')
/home/esc/git-working/scipy-lecture-notes/advanced/interfacing_with_c/ctypes/cos_module.py in cos_func(arg) 12 def cos_func(arg): 13 ''' Wrapper for cos from math.h ''' ---> 14 return libm.cos(arg)
ArgumentError: argument 1: <type 'exceptions.TypeError'>: wrong type
voidcos_doubles(double * in_array, double * out_array, int size);
这个实现在C源码中如下:
1 2 3 4 5 6 7 8 9 10
#include<math.h>
/* Compute the cosine of each element in in_array, storing the result in * out_array. */ voidcos_doubles(double * in_array, double * out_array, int size){ int i; for(i=0;i<size;i++){ out_array[i] = cos(in_array[i]); } }
""" Example of wrapping a C library function that accepts a C double array as input using the numpy.ctypeslib. """
import numpy as np import numpy.ctypeslib as npct from ctypes import c_int
# input type for the cos_doubles function # must be a double array, with single dimension that is contiguous array_1d_double = npct.ndpointer(dtype=np.double, ndim=1, flags='CONTIGUOUS')
# load the library, using numpy mechanisms libcd = npct.load_library("libcos_doubles", ".")
# setup the return typs and argument types libcd.cos_doubles.restype = None libcd.cos_doubles.argtypes = [array_1d_double, array_1d_double, c_int]
/* Example of wrapping cos function from math.h using SWIG. */
%module cos_module %{ /* the resulting C file should be built as a python extension */ #define SWIG_FILE_WITH_INIT /* Includes the header in the wrapper code */ #include"cos_module.h" %} /* Parse the header file to generate wrappers */ %include "cos_module.h"
voidcos_doubles(double * in_array, double * out_array, int size);
1 2 3 4 5 6 7 8 9 10
#include <math.h>
/* Compute the cosine of each element in in_array, storing the result in * out_array. */ void cos_doubles(double * in_array, double * out_array, int size){ int i; for(i=0;i<size;i++){ out_array[i] = cos(in_array[i]); } }
/* Example of wrapping a C function that takes a C double array as input using * numpy typemaps for SWIG. */
%module cos_doubles %{ /* the resulting C file should be built as a python extension */ #define SWIG_FILE_WITH_INIT /* Includes the header in the wrapper code */ #include"cos_doubles.h" %}
/* include the numpy typemaps */ %include "numpy.i" /* need this for correct module initialization */ %init %{ import_array(); %}
/* typemaps for the two arrays, the second will be modified in-place */ %apply (double* IN_ARRAY1, int DIM1) {(double * in_array, int size_in)} %apply (double* INPLACE_ARRAY1, int DIM1) {(double * out_array, int size_out)}
/* Wrapper for cos_doubles that massages the types */ %inline %{ /* takes as input two numpy arrays */ voidcos_doubles_func(double * in_array, int size_in, double * out_array, int size_out){ /* calls the original funcion, providing only the size of the first */ cos_doubles(in_array, out_array, size_in); } %}
voidcos_doubles(double * in_array, double * out_array, int size);
1 2 3 4 5 6 7 8 9 10
#include<math.h>
/* Compute the cosine of each element in in_array, storing the result in * out_array. */ voidcos_doubles(double * in_array, double * out_array, int size){ int i; for(i=0;i<size;i++){ out_array[i] = cos(in_array[i]); } }
To follow the path:(沿着这样一条道路:) look to the master,(寻找大师,) follow the master,(跟随大师,) walk with the master,(与大师通行,) see through the master,(洞察大师,) become the master.(成为大师。)
You can’t connect the dots looking forward you can only connect them looking backwards. So you have to trust that the dots will somehow connect in your future. You have to trust in something: your gut, destiny, life, karma, whatever. Because believing that the dots will connect down the road will give you the confidence to follow your heart, even when it leads you off the well worn path.
>>> nums = [1,2,3] # note that ... varies: these are different objects >>> iter(nums) <listiterator object at ...> >>> nums.__iter__() <listiterator object at ...> >>> nums.__reversed__() <listreverseiterator object at ...>
>>> import itertools >>> defg(): ... print'--start--' ... for i in itertools.count(): ... print'--yielding %i--' % i ... try: ... ans = yield i ... except GeneratorExit: ... print'--closing--' ... raise ... except Exception as e: ... print'--yield raised %r--' % e ... else: ... print'--yield returned %s--' % ans
>>> defdecorator_with_arguments(arg): ... print"defining the decorator" ... def_decorator(function): ... # in this inner function, arg is available too ... print"doing decoration,", arg ... return function ... return _decorator >>> @decorator_with_arguments("abc") ... deffunction(): ... print"inside function" defining the decorator doing decoration, abc >>> function() inside function
>>> classdecorator_class(object): ... def__init__(self, arg): ... # this method is called in the decorator expression ... print"in decorator init,", arg ... self.arg = arg ... def__call__(self, function): ... # this method is called to do the job ... print"in decorator call,", self.arg ... return function >>> deco_instance = decorator_class('foo') in decorator init, foo >>> @deco_instance ... deffunction(*args, **kwargs): ... print"in function,", args, kwargs in decorator call, foo >>> function() in function, () {}
classassert_raises(object): # based on pytest and unittest.TestCase def__init__(self, type): self.type = type def__enter__(self): pass def__exit__(self, type, value, traceback): if type isNone: raise AssertionError('exception expected') if issubclass(type, self.type): returnTrue# swallow the expected exception raise AssertionError('wrong exception type')
在ctags的例子中,我们没告诉Portage有关任何依赖。当情况是这样时,没关系,因为ctags仅仅需要一个基本的工具链来编译和运行(参见Implicit System Dependency理解为何我们不需要显式依赖)。然而事情很少这么简单。
这是app-misc/detox/detox-1.1.1.ebuild:
# Copyright 1999-2012 Gentoo Foundation# Distributed under the terms of the GNU General Public License v2# $Header: $EAPI=4DESCRIPTION="detox safely removes spaces and strange characters from filenames"HOMEPAGE="http://detox.sourceforge.net/"SRC_URI="mirror://sourceforge/${PN}/${P}.tar.bz2"LICENSE="BSD"SLOT="0"KEYWORDS="~hppa ~mips sparc x86"RDEPEND="dev-libs/popt"DEPEND="${RDEPEND}
sys-devel/flex
sys-devel/bison"
src_configure() {
econf --with-popt
}
src_install() {
emake DESTDIR="${D}" install
dodoc README CHANGES
}
# Copyright 1999-2012 Gentoo Foundation# Distributed under the terms of the GNU General Public License v2# $Header: $
EAPI=4
inherit eutils
DESCRIPTION="detox safely removes spaces and strange characters from filenames"
HOMEPAGE="http://detox.sourceforge.net/"
SRC_URI="mirror://sourceforge/${PN}/${P}.tar.bz2"
LICENSE="BSD"
SLOT="0"
KEYWORDS="~hppa ~mips ~sparc ~x86"
RDEPEND="dev-libs/popt"
DEPEND="${RDEPEND}
sys-devel/flex
sys-devel/bison"src_prepare() {
epatch "${FILESDIR}"/${P}-destdir.patch \
"${FILESDIR}"/${P}-parallel_build.patch
}
src_configure() {
econf --with-popt
}
src_install() {
emake DESTDIR="${D}" install
dodoc README CHANGES
}
注意${FILESDIR}/${P}-destdir.patch指向detox-1.1.0-destdir.patch,这个文件在Portage树的files/子文件夹中。更大的补丁文件必须在你的开发者空间dev.gentoo.org而不是files/或镜像中——参见Gentoo Mirrors和Patching with epatch。
# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $
EAPI=4
DESCRIPTION="GNU charset conversion library for libc which doesn't implement it"HOMEPAGE="http://www.gnu.org/software/libiconv/"SRC_URI="ftp://ftp.gnu.org/pub/gnu/libiconv/${P}.tar.gz"
LICENSE="LGPL-2.1"SLOT="0"KEYWORDS="~amd64 ~ppc ~sparc ~x86"IUSE="nls"
DEPEND="!sys-libs/glibc"
src_configure() {
econf $(use_enable nls)
}
src_install() {
emake DESTDIR="${D}" install
}
defmakeHTMLbox(body, fontsize, imagesize): """takes one long string of words and a width(px) then put them in an HTML box""" boxStr = """<div style=\"font-size: %spx;line-height: 100%s; width: %s;background-color: rgb(0, 0, 0);border: 1px grey solid;text-align: center; overflow: hidden;\">%s</div> """ return boxStr % (fontsize, '%', imagesize[0], body)
defmakeHTMLascii(body, color): """take words and , and create an HTML word """ #num = str(random.randint(0,255)) # return random color for every tags color = 'rgb(%s, %s, %s)' % color # get the html data wordStr = '<span style=\"color:%s;float:left;\">%s</span>' return wordStr % (color, body)
defi2m(im, fontsize): """turn an image into ascii like matrix""" im = im.convert('L') im = ImageOps.autocontrast(im) im.thumbnail((im.size[0] / fontsize, im.size[1] / fontsize)) string = '' colors = [(0, i, 0) for i in range(0, 256, 17)] words = '据说只有到了十五字才会有经验的' for y in range(im.size[1]): for x in range(im.size[0]): p = im.getpixel((x, y)) i = 14 while i >= 0: if p >= i * 17: s = makeHTMLascii(words[3 * i:3 * (i + 1)], colors[i]) break i -= 1 if x % im.size[0] == 0and y > 0: s = s + '<br/>' string = string + s return string
defi2a(im, fontsize): """turn an image into ascii with colors""" im = im.convert('RGB') im = ImageOps.autocontrast(im) im.thumbnail((im.size[0] / fontsize, im.size[1] / fontsize)) string = '' for y in range(im.size[1]): for x in range(im.size[0]): c = im.getpixel((x, y)) # print c s = makeHTMLascii('翻', c) if x % im.size[0] == 0and y > 0: s = s + '<br/>' string = string + s return string
defgetHTMLascii(filename, fontsize, style='matrix', outputfile='a.html', scale=1): """Got html ascii image""" im = Image.open(filename) size = (int(im.size[0] * scale), int(im.size[1] * scale)) im.thumbnail(size, Image.ANTIALIAS) if style == 'matrix': ascii = makeHTMLbox(i2m(im, fontsize), fontsize, im.size) elif style == 'ascii': ascii = i2a(im, fontsize) else: print"Just support ascii and matrix now, fall back to matrix" ascii = makeHTMLbox(i2m(im, fontsize), fontsize, im.size) with open(outputfile, 'wb') as f: f.write(ascii) return1
Update: Mon 25 Feb 2013 11:38:47 AM CST add classic style. More refer to github
Python是面向对象的?没有对象面向毛对象。
——Anonymous
Several weeks ago, I saw a poster of presidential campaign for Obama, in which Obama’s portrait was made up of many voter’s photos. It really attracted me, somedays later, I want to make one myself.
The completed code host here. It is much more functional than object-oriented…
Search the Internet
First of all, I searched the Google to find out how others achieve it, then I found many interesting implement and post on it.Along with them, there are pretty demos around.One of the demo of Foto-Mosaik-Edda striked me.It declaims as follows in their site:
The Chaos Mosaic Picture is a new form of photo mosaic which can, at present, only be created by Foto-Mosaik-Edda.
Uhm…Foto-Mosaic-Edda is an open-source project that really impressive.But it was an C# project. Linux users don’t like it however.I don’t like mono.
I searched other open-source implement on photomosaic. I get some simple programs only use gray photos, and some complex ones can make beautiful classic photomosaic(like metapixel, even chaos style which it calls collage style), But none has as beautiful demos as Foto-Mosaic-Edda.(metapixel really amazing, it is robust and quickly.)
However, I saw many enthusiastic people write one themselves, it really looks interesting for me. I’ve used PIL for processing images when I tried to decode captchas several days ago, so I believe with the help of PIL, someone can achieve photomosaic simply.
So I just read the documentation of PIL, then start my hack.
Write My Own PhotoMosaic Generator
It’s not hard, however, what you should do is clear and simple:
analyse the image to be made mosaic, get a dict in which position as key and color as value.
use a bunch of images to get a dict, in which image name as key and colors as value.
thumbnail bunches of images and paste it in the right position, so that the big image looks like it consists of many small one.
I’d like to got the chaos style, so some other requirements:
defadd_frame(image): '''Add frame for image.''' im = ImageOps.expand(image, border=int(0.01 * max(image.size)), fill=0xffffff) return im
defdrop_shadow(image, offset, border=0, shadow_color=0x444444): """Add shadows for image""" # Caclulate size fullWidth = image.size[0] + abs(offset[0]) + 2 * border fullHeight = image.size[1] + abs(offset[1]) + 2 * border # Create shadow, hardcode color shadow = Image.new('RGBA', (fullWidth, fullHeight), (0, 0, 0)) # Place the shadow, with required offset shadowLeft = border + max(offset[0], 0) # if <0, push the rest of the image right shadowTop = border + max(offset[1], 0) # if <0, push the rest of the image down shadow.paste(shadow_color, [shadowLeft, shadowTop, shadowLeft + image.size[0], shadowTop + image.size[1]]) shadow_mask = shadow.convert("L") # Paste the original image on top of the shadow imgLeft = border - min(offset[0], 0) # if the shadow offset was <0, push right imgTop = border - min(offset[1], 0) # if the shadow offset was <0, push down shadow.putalpha(shadow_mask) shadow.paste(image, (imgLeft, imgTop)) return shadow
Then a function to rotate images.
1 2 3 4 5 6
defrotate_image(image, degree): '''Rotate images for specific degree. Expand to show all''' if image.mode != 'RGBA': image = image.convert('RGBA') im = image.rotate(degree, expand=1) return im
‘RGBA’ mode is to support transparency. What’s matter here is that jpeg/jpg does not support transparency. So you can’t get transparency shadows and rotate pictures if you just use jpg/jpeg images.So, write a function to process images with jpg/jpeg format, transpose it into png.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
defprocess_image(filename, newname): '''convert image to png to support transparency''' if filename.split('.')[-1] != 'png': im = Image.open(filename) im.save(newname + '.png') print"processing image file %s" % filename return1
defprocess_directory(path): os.chdir(path) count = 1 for filename in os.listdir(path): ext = filename.split('.')[-1] if ext == 'jpeg'or ext == 'jpg': process_image(filename, str(count)) os.remove(filename) count += 1 return1
Really poor work… But it works for me: )
We have to thumnail bunches of images, It’s easy to thumbnail with PIL:
1 2 3 4
defthumbnail(im, size): """thumnail the image""" im.thumbnail(size, Image.ANTIALIAS) return im
Let’s have a fun with them. To get heaps of images randomly on the desktop, I hardcoded these parameters to get my photos work, you HAVE TO find yours:
1 2 3 4 5 6 7 8 9 10
# Just for fun defchao_image(path, size=(800, 800), thumbnail_size=(50, 50), shadow_offset=(10, 10), backgroud_color=0xffffff): image_all = Image.new('RGB', size, backgroud_color) for image in os.listdir(path): if image.split('.')[-1] == 'png': im = Image.open(image) degree = random.randint(-30, 30) im = thumbnail(rotate_image(drop_shadow(add_frame(im), shadow_offset), degree), thumbnail_size) image_all.paste(im, (random.randint(-thumbnail_size[0], size[0]), random.randint(-thumbnail_size[1], size[1])), im) return image_all
Calculate Images And Compare
Get average colors of an image
1 2 3 4
defaverage_image(im): """return average (r,g,b) for image""" color_vector = [int(x) for x in ImageStat.Stat(im).mean] return color_vector
to compare images? Compare the (r,g,b) value of them.
1 2 3 4 5 6 7 8 9
defcompare_vectors(v1, v2): """compare image1 and image2, return relations""" if len(v1) == len(v2): distance = 0 for i in xrange(len(v1)): distance += (v1[i] - v2[i]) ** 2 return distance else: print"vector not match in dimensions"
I just use distance in (R, G, B) space to calculate similarity, someone advice compare in other space, you can change it just like the example in PIL’s documentation:
1 2 3 4 5 6
# May not useful defrgb2xyz(im): """rgb to xyz""" rgb2xyz = (0.412453, 0.357580, 0.180423, 0, 0.212671, 0.715160, 0.072169, 0, 0.019334, 0.119193, 0.950227, 0) out = im.convert("RGB", rgb2xyz) return out
But I find many implements just use R,G,B, and it works well.
Next, get a dict of image in current path, in which filename as key, average (R,G,B) colors as value.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
deftile_dict(path): """Return list of average (R,G,B) for image in this path as dict.""" dic = {} for image in os.listdir(path): if image.split('.')[-1] == 'png': try: im = Image.open(image) except: print"image file %s cannot open" % image continue if im.mode != 'RGB': im = im.convert('RGB') dic[image] = average_image(im) return dic
We don’t need to calculate every pixel of the large picture, just thumbnail it to get a nearest color of different regions.
1 2 3 4 5 6
defthumbnail_background(im, scale): """thumbnail backgroud image""" newsize = im.size[0] / scale, im.size[1] / scale im.thumbnail(newsize) print'thumbnail size and the number of tiles %d X %d' % im.size return im.size
For every pixel in the thumbnailed large image, find most similar small image filenames.(top ten):
1 2 3 4 5 6 7 8 9 10
deffind_similar(lst, dic): """for lst([R, G, B], Calculate which key-value in dic has the most similarity.Return first 10)""" similar = {} for k, v in dic.items(): similar[k] = compare_vectors(v, lst) # if len(v) != len(lst): # print v, len(v), lst, len(lst) similar = [(v, k) for k, v in similar.items()] # Not good, lost the same Score similar.sort() return similar[:10]
Poor hack, but it really works…
Final Work
Now it’s the final magic.
Get the small image in order, the order imply where it should be. Then rotate, add shadows and frames for small images, finally paste it onto the large one randomly in the right position:
defget_image_list(im, dic): """receive a thumbnail image and a dict of image to be mosaic, return tiles(filename) in order(as a list)""" lst = list(im.getdata()) tiles = [] for i in range(len(lst)): #print find_similar(lst[i], dic)[random.randrange(10)][1] tiles.append(find_similar(lst[i], dic)[random.randrange(10)][1]) return tiles defpaste_chaos(image, tiles, size, shadow_off_set=(30, 30)): """size is thumbnail of backgroud size that is how many tiles per line and row""" # image_all = Image.new('RGB', image.size, 0xffffff) image_all = image lst = range(len(tiles)) random.shuffle(lst) fragment_size = (image.size[0] / size[0], image.size[1] / size[1]) print'tiles size %d X %d' % fragment_size print'number of tiles one iteration: %d' % len(lst) for i in lst: im = Image.open(tiles[i]) degree = random.randint(-20, 20) im = thumbnail(rotate_image(drop_shadow(add_frame(im), shadow_off_set), degree), (fragment_size[0] * 3 / 2, fragment_size[1] * 3 / 2)) x = i % size[0] * fragment_size[0] + random.randrange(-fragment_size[0] / 2, fragment_size[0] / 2) y = i / size[0] * fragment_size[1] + random.randrange(-fragment_size[1] / 2, fragment_size[1] / 2) # print x, y image_all.paste(im, (x, y), im) return image_all
I try it like this, I know parameter n is tricky, it was the scale it thumbnail the large image. Maybe I’ll change it to something more clear later…
defmain(filename, n, scale, iteration, path='./'): # 0. select an big image for mosaic print"open %s" % filename im = Image.open(filename) # 1. process image as png to support transparency print"process directory %s" % path process_directory(path) # 2. get a dict for path print"get tile dict for path `%s`" % path try: with open('dic.txt', 'r') as f: dic = p.load(f) except: dic = tile_dict(path) with open('dic.txt', 'wb') as f: p.dump(dic, f) # 3. thumbnail the big image for compare print"thumbnail background for compare" # n = 30 # 原始图片缩为多少分之一 # scale = 3 # 原始图片放大倍数 big_size = im.size[0] * scale, im.size[1] * scale im_chao = Image.new('RGB', big_size, 0xffffff) imb_t_size = thumbnail_background(im, n) print"how may tiles: %d X %d" % imb_t_size print'number of iterations: %d' % iteration for i in range(iteration): print'iteration: %d' % (i + 1) # 4. get a list of smail image for mosaic print"get pic list" im_tiles = get_image_list(im, dic) # 5. paste in chaos style print"generate final image" im_chao = paste_chaos(im_chao, im_tiles, imb_t_size) return im_chao
if __name__ == '__main__': im = main('../mm.jpg', 15, 5, 2) im.save('../final3.png') im.show()